"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isModuleHTMLFile = exports.retrieveDefaultModule = exports.createModule = exports.validateSrcAndDestPaths = exports.ValidationIds = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_2 = require("../path");
const fs_1 = require("../fs");
const github_1 = require("../github");
const logger_1 = require("../logger");
const modules_1 = require("../../utils/cms/modules");
const lang_1 = require("../../utils/lang");
const i18nKey = 'lib.cms.modules';
// Ids for testing
exports.ValidationIds = {
    SRC_REQUIRED: 'SRC_REQUIRED',
    DEST_REQUIRED: 'DEST_REQUIRED',
    MODULE_FOLDER_REQUIRED: 'MODULE_FOLDER_REQUIRED',
    MODULE_TO_MODULE_NESTING: 'MODULE_TO_MODULE_NESTING',
    MODULE_NESTING: 'MODULE_NESTING',
};
const getValidationResult = (id, message) => ({ id, message });
async function validateSrcAndDestPaths(src, dest) {
    const results = [];
    if (!(0, modules_1.isPathInput)(src)) {
        results.push(getValidationResult(exports.ValidationIds.SRC_REQUIRED, '`src` is required.'));
    }
    if (!(0, modules_1.isPathInput)(dest)) {
        results.push(getValidationResult(exports.ValidationIds.DEST_REQUIRED, '`dest` is required.'));
    }
    if (results.length || !src || !dest) {
        return results;
    }
    const [_src, _dest] = [src, dest].map(inputPath => {
        const result = { ...inputPath };
        if (result.isLocal) {
            result.path = path_1.default.resolve((0, path_2.getCwd)(), result.path);
        }
        else if (result.isHubSpot) {
            result.path = path_1.default.posix.normalize(result.path);
        }
        return result;
    });
    // src is a .module folder and dest is within a module. (Nesting)
    // e.g. `upload foo.module bar.module/zzz`
    if ((0, modules_1.isModuleFolder)(_src) && (0, modules_1.isModuleFolderChild)(_dest)) {
        return results.concat(getValidationResult(exports.ValidationIds.MODULE_TO_MODULE_NESTING, '`src` is a module path and `dest` is within a module.'));
    }
    // src is a .module folder but dest is not
    // e.g. `upload foo.module bar`
    if ((0, modules_1.isModuleFolder)(_src) && !(0, modules_1.isModuleFolder)(_dest)) {
        return results.concat(getValidationResult(exports.ValidationIds.MODULE_FOLDER_REQUIRED, '`src` is a module path but `dest` is not.'));
    }
    // src is a folder that includes modules and dest is within a module. (Nesting)
    if (_src.isLocal && (0, modules_1.isModuleFolderChild)(_dest)) {
        const stat = await fs_extra_1.default.stat(_src.path);
        if (stat.isDirectory()) {
            const files = await (0, fs_1.walk)(_src.path);
            const srcHasModulesChildren = files.some(file => (0, modules_1.isModuleFolderChild)({ ..._src, path: file }));
            if (srcHasModulesChildren) {
                return results.concat(getValidationResult(exports.ValidationIds.MODULE_NESTING, '`src` contains modules and `dest` is within a module.'));
            }
        }
    }
    return results;
}
exports.validateSrcAndDestPaths = validateSrcAndDestPaths;
/* createModule() helper
 * Takes a file and uses the constants above to transform the contents
 */
// Strings to replace in React module files
const MODULE_STRING_TRANSFORMATIONS = [
    {
        regex: /\/\* import global styles \*\//g,
        string: 'import "./global-sample-react-module.css";',
        fallback: '',
    },
    {
        regex: /\/\* Default config \*\//g,
        string: 'export const defaultModuleConfig = { \n  moduleName: "sample_react-module", \n  version: 0, \n};',
        fallback: '',
    },
];
const updateFileContents = async (file, metaData, getInternalVersion) => {
    try {
        let fileContents = await fs_extra_1.default.readFile(file, 'utf8'); // returns Promise
        MODULE_STRING_TRANSFORMATIONS.forEach(entry => {
            const replacementString = getInternalVersion
                ? entry.string
                : entry.fallback;
            fileContents = fileContents.replace(entry.regex, replacementString);
        });
        await fs_extra_1.default.writeFile(file, fileContents, 'utf8');
        await fs_extra_1.default.appendFile(file, 'export const meta = ' + JSON.stringify(metaData, null, ' '));
    }
    catch (error) {
        const { message } = error;
        throw new Error((0, lang_1.i18n)(`${i18nKey}.createModule.errors.fileUpdateFailure`, {
            path: file,
            errorMessage: message,
        }));
    }
};
async function createModule(moduleDefinition, name, dest, getInternalVersion, options = {
    allowExistingDir: false,
}) {
    const { moduleLabel, contentTypes, global, reactType: isReactModule, availableForNewContent, } = moduleDefinition;
    const moduleMetaData = {
        label: moduleLabel,
        css_assets: [],
        external_js: [],
        global: global,
        help_text: '',
        content_types: contentTypes,
        js_assets: [],
        other_assets: [],
        smart_type: 'NOT_SMART',
        tags: [],
        is_available_for_new_content: availableForNewContent,
    };
    const folderName = name.endsWith('.module') ? name : `${name}.module`;
    const destPath = !isReactModule
        ? path_1.default.join(dest, folderName)
        : path_1.default.join(dest, `${name}`);
    if (!options.allowExistingDir && fs_extra_1.default.existsSync(destPath)) {
        throw new Error((0, lang_1.i18n)(`${i18nKey}.createModule.errors.pathExists`, {
            path: destPath,
        }));
    }
    else {
        logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.createModule.creatingPath`, {
            path: destPath,
        }));
        fs_extra_1.default.ensureDirSync(destPath);
    }
    logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.createModule.creatingModule`, {
        path: destPath,
    }));
    // Filter out certain fetched files from the response
    const moduleFileFilter = (src) => {
        const emailEnabled = moduleDefinition.contentTypes.includes('EMAIL');
        switch (path_1.default.basename(src)) {
            case 'meta.json':
                return false;
            case 'module.js':
            case 'module.css':
                return !emailEnabled;
            case 'global-sample-react-module.css':
                return getInternalVersion;
            default:
                return true;
        }
    };
    // Download gitHub contents to the dest directory
    const sampleAssetPath = !isReactModule
        ? 'Sample.module'
        : 'SampleReactModule';
    const sourceDir = `modules/${sampleAssetPath}`;
    await (0, github_1.cloneGithubRepo)('HubSpot/cms-sample-assets', destPath, {
        sourceDir,
    });
    const files = await (0, fs_1.walk)(destPath);
    files
        .filter(filePath => !moduleFileFilter(filePath))
        .forEach(filePath => {
        fs_extra_1.default.unlinkSync(filePath);
    });
    if (!getInternalVersion) {
        fs_extra_1.default.removeSync(path_1.default.join(destPath, 'stories'));
        fs_extra_1.default.removeSync(path_1.default.join(destPath, 'tests'));
    }
    // Get and write the metafiles
    const metaFiles = files.filter(filePath => path_1.default.basename(filePath) === 'meta.json');
    metaFiles.forEach(metaFile => {
        fs_extra_1.default.writeJSONSync(metaFile, moduleMetaData, {
            spaces: 2,
        });
    });
    // Updating React module files after fetch
    if (isReactModule) {
        await updateFileContents(`${destPath}/index.tsx`, moduleMetaData, getInternalVersion);
    }
}
exports.createModule = createModule;
async function retrieveDefaultModule(name, dest) {
    if (!name) {
        const defaultReactModules = await (0, github_1.listGithubRepoContents)('HubSpot/cms-react', 'default-react-modules/src/components/modules/', 'dir');
        return defaultReactModules;
    }
    if (dest) {
        await (0, github_1.cloneGithubRepo)('HubSpot/cms-react', dest, {
            sourceDir: `default-react-modules/src/components/modules/${name}`,
        });
    }
}
exports.retrieveDefaultModule = retrieveDefaultModule;
const MODULE_HTML_EXTENSION_REGEX = new RegExp(/\.module(?:\/|\\)module\.html$/);
const isModuleHTMLFile = (filePath) => MODULE_HTML_EXTENSION_REGEX.test(filePath);
exports.isModuleHTMLFile = isModuleHTMLFile;
